package com.xemotion.weceem.services

import org.weceem.files.WcmContentFile
import org.weceem.files.WcmContentDirectory

import com.xemotion.weceem.files.WcmContentFileBin

import org.apache.commons.logging.LogFactory
import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.codehaus.groovy.grails.commons.ConfigurationHolder

import groovyx.net.http.AsyncHTTPBuilder
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*


/**
 * ClusterManagerService
 * @author yasumasa Note
 * 
 * Message modify content to other cluster nodes with JSON-RPC.
 */
class ClusterManagerService {
    private static def log = LogFactory.getLog('com.xemotion.weceem.services.ClusterManagerService')

    static transactional = true
	
    private static def manager = ConfigurationHolder.config.weceem.cluster.manager
    private static def nodes = ConfigurationHolder.config.weceem.cluster.nodes
    private static def path = ConfigurationHolder.config.weceem.cluster.contloller.uri
    private static def username = ConfigurationHolder.config.weceem.cluster.contloller.username ?: ''
    private static def password = ConfigurationHolder.config.weceem.cluster.contloller.password ?: ''

    /**
     * Save binary data from a WcmContentFile entity.
     * Message creating contents to other nodes in cluster.
     * @param content WcmContentFile
     */
    public void createContent(content) {
        if (content instanceof WcmContentFile && !(content instanceof WcmContentDirectory)) {
            // delete same resourcePath ContentFileBin
            WcmContentFileBin.findAllByResourcePath(content.toResourcePath()).each {
                it.delete(flash:true)
            }
		   
            // save ContentFileBin to restore files
            def f = new File( ServletContextHolder.servletContext.getRealPath(content.toResourcePath()) )
            def mt = content.fileMimeType ?: WcmContentFile.getDefaultMimeType(content.aliasURI)
            def file_bin = new WcmContentFileBin(
                wcmContentId: content.id,
                data: f.bytes,
                resourcePath: content.toResourcePath(),
                relativePath: content.toRelativePath(),
                fileName: content.aliasURI,
                fileMimeType: mt,
                fileSize: content.fileSize
            )
            if (file_bin.save(flash:true)) {
                log.debug "Binary data of '${file_bin.fileName}' is saved."
            } else {
                log.debug "Failed to save binary data of '${file_bin.fileName}'."
            }
		   
            def base64_bin = f.bytes.encodeAsBase64()
            withAsyncHttp(poolSize: 10, timeout: 10000, contentType: JSON) {
                def _log = LogFactory.getLog('com.xemotion.weceem.services.ClusterManagerService')
                for (node in nodes) {
                    if (node != manager) {
                        def body = [method: "addFile", path: content.toResourcePath(), data: base64_bin]
                        post(uri: "http://${node}${path}", body: body, requestContentType: JSON) { req, json ->
                            if (json.result == 1) {
                                _log.debug "JSON-RPC success. uri:http://${node}${path} method:createContentFile path:${content.toResourcePath()}"
                            } else {
                                _log.error "JSON-RPC failure. uri:http://${node}${path} method:createContentFile path:${content.toResourcePath()}"
                            }
                        }
                    }
                }
            }
        }
    }
   
    /**
     * Message invalidate cache of updated content to other nodes.
     * @param content
     */
    public void updateContent(content) {
        def cache_path = content.space.aliasURI + '/' + content.absoluteURI
        log.debug "cache_path: " + cache_path
		
        withAsyncHttp(poolSize: 10, timeout: 10000, contentType: JSON) {
            def _log = LogFactory.getLog('com.xemotion.weceem.services.ClusterManagerService')
            for (node in nodes) {
                if (node != manager) {
                    def body = [method: "invalidateCaching", path: cache_path]
                    post(uri: "http://${node}${path}", body: body, requestContentType: JSON) { req, json ->
                        if (json.result == 1) {
                            _log.debug "JSON-RPC success. uri:http://${node}${path} method:invalidateCaching path:${cache_path}"
                        } else {
                            _log.error "JSON-RPC failure. uri:http://${node}${path} method:invalidateCaching path:${cache_path}"
                        }
                    }
                }
            }
        }
		
    }

    /**
     * Message deleting content to other nodes.
     * Concretely at other nodes deleting server files and invalidating cached.
     * @param content
     */
    public void deleteContent(content) {
        if (content instanceof WcmContentFile && !(content instanceof WcmContentDirectory)) {
            def resource_path = content.toResourcePath()
			
            // delete same resourcePath ContentFileBin
            WcmContentFileBin.findAllByResourcePath(resource_path).each {
                it.delete(flush:true)
            }
			
            withAsyncHttp(poolSize: 10, timeout: 10000, contentType: JSON) {
                def _log = LogFactory.getLog('com.xemotion.weceem.services.ClusterManagerService')
                for (node in nodes) {
                    if (node != manager) {
                        def body = [method: "removeFile", path: resource_path]
                        post(uri: "http://${node}${path}", body: body, requestContentType: JSON) { req, json ->
                            if (json.result == 1) {
                                _log.debug "JSON-RPC seccess. uri:http://${node}${path} method:deleteContent path:${resource_path}"
                            } else {
                                _log.error "JSON-RPC failure. uri:http://${node}${path} method:deleteContent path:${resource_path}"
                            }
                        }
                    }
                }
            }
        }
		
        // invalidateCaching
        updateContent(content)
    }

}
